#include "cylinder.h"
#include "plane.h"
#include <limits>

CCylinder::CCylinder(SCALAR r, SCALAR h, VECTOR &l):rad(r), height(h), loc(l) {
}

CCylinder::~CCylinder(void)
{
}

bool CCylinder::hits (const CLine &line, SCALAR &t_hit) {
	CLine transposedLine = CLine(line.loc - loc, line.dir, 0);

	//Comprobem amb la tapa INF:
	CPlane plInf = CPlane(VECTOR(0,1,0), 0);
	bool objectHit = false;
	SCALAR t_tapa = std::numeric_limits<float>::max();
	SCALAR thit;
	
	if(plInf.hits(transposedLine, thit))
	{
		VECTOR plInters = transposedLine.loc + (transposedLine.dir*thit);

		if(plInters.x*plInters.x + plInters.z*plInters.z <= rad*rad)
		{
				objectHit = true;
				t_tapa = thit;
			
		}
	}
	//Comprobem amb la tapa UP:
	CPlane plUp = CPlane(VECTOR(0,1,0), height);
	if(plUp.hits(transposedLine, thit))
	{
		VECTOR plInters = transposedLine.loc + (transposedLine.dir*thit);

		if(plInters.x*plInters.x + plInters.z*plInters.z <= rad*rad)
		{
			objectHit = true;
			t_tapa = thit;
			
		}
	}

	//Comprobem amb el cos:
	SCALAR a,b,c,discriminant;
	SCALAR t1 = -1;
	SCALAR t2 = -1;
	SCALAR t;
	a = transposedLine.dir.x*transposedLine.dir.x + transposedLine.dir.z*transposedLine.dir.z;
	b = transposedLine.loc.x*transposedLine.dir.x + transposedLine.loc.z*transposedLine.dir.z;
	b *= 2;
	c = transposedLine.loc.x*transposedLine.loc.x + transposedLine.loc.z*transposedLine.loc.z - rad*rad;

	discriminant=((b*b)-4*a*c);
	if(discriminant>0)
	{
		t2=(-1*b-sqrt(discriminant))/(2*a);
		t1=(-1*b+sqrt(discriminant))/(2*a);
	}
	else if(discriminant==0)
	{
		t1 = t2 = (-1*b)/(2*a);
	}
	if(t2 > SMALL_AMOUNT)
		t = t2;
	else if(t1 > SMALL_AMOUNT)
		t = t1;
	else if (!objectHit)
		return false;

	VECTOR inters = transposedLine.loc + (transposedLine.dir*t);
	if(inters.y >= 0 && inters.y <= height)
	{
		objectHit = true;
	}
	if(t < t_tapa)
		t_hit = t;
	else
		t_hit = t_tapa;

	return objectHit;
}

VECTOR CCylinder::getNormal (const VECTOR &aloc) {
	if(aloc.y >= height + loc.y - SMALL_AMOUNT)
		return VECTOR(0,1,0);
	else if(aloc.y <= 0 + loc.y + SMALL_AMOUNT)
		return VECTOR(0,-1,0);
	else
	{
		return VECTOR((aloc.x - loc.x)/rad, 0, (aloc.z - loc.z)/rad);
	}
}
